﻿using HslCommunication.MQTT;
using HuanReZhanDataReceiver;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.TaskbarClock;

namespace FlowerPot
{
    public partial class Form1 : Form
    {
        // 创建一个和客户端通信的套接字
        static Socket socketwatch = null;
        //定义一个集合，存储客户端信息
        static Dictionary<string, Socket> clientConnectionItems = new Dictionary<string, Socket> { };

        private Thread threadwatch = null;

        private static Form1 instance = null;

        private static SqlHelper sqlHelper = new SqlHelper();

        private static List<CommandInfo> commandToSend = new List<CommandInfo>();

        private DateTime lastCheckMoveHistoryData = DateTime.MinValue;

        private static DateTime lastSendReadStatus = DateTime.MinValue;

        private MqttClient client;

        private Thread serverThread = null;

        private bool canSend = false;


        private static RestClient restClient;

        private static DateTime lastGetData = DateTime.Now;

        private Int32 autoRestartWhenNoReceiveDataInMinites = 30;

        private static Dictionary<String, String> endPointStrAndStationId = new Dictionary<string, string>();

        public static Form1 getInstance()
        {
            if (instance == null)
            {
                instance = new Form1();
            }

            return instance;
        }


        public Form1()
        {
            Control.CheckForIllegalCrossThreadCalls = false;
            InitializeComponent();

            txtIP.Text = ConfigurationManager.AppSettings["ServerIP"];
            txtPort.Text = ConfigurationManager.AppSettings["ServerPort"];

            if (Boolean.Parse(ConfigurationManager.AppSettings["AutoStart"]) == true)
            {
                tmrForStart.Enabled = true;
                tmrForStart.Start();
            }

            tmrCheckMoveHistory.Enabled = false;
            tmrCheckMoveHistory.Start();

            if (ConfigurationManager.AppSettings["AutoRestartWhenNoReceiveDataInMinites"] != null)
            {
                autoRestartWhenNoReceiveDataInMinites = Int32.Parse(ConfigurationManager.AppSettings["AutoRestartWhenNoReceiveDataInMinites"]);
            }
            else
            {
                autoRestartWhenNoReceiveDataInMinites = 30;
            }

            txtNoDataInMiniutes.Text = autoRestartWhenNoReceiveDataInMinites.ToString();

            this.Text = ConfigurationManager.AppSettings["ProjectName"] + "：" + ConfigurationManager.AppSettings["version"];

            restClient = new RestClient();

        }

        private void button1_Click(object sender, EventArgs e)
        {
            if (btStart.Text.Equals("启动"))
            {
                showLogs(DateTime.Now.Subtract(new TimeSpan(0, int.Parse(Form1.getInstance().txtMiniute.Text), 0)).ToString("yyyy-MM-dd HH:mm:ss") + "-" + "服务器端启动。\r\n");

                try
                {
                    //定义一个套接字用于监听客户端发来的消息，包含三个参数（IP4寻址协议，流式连接，Tcp协议）  
                    socketwatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                    //服务端发送信息需要一个IP地址和端口号  
                    IPAddress address = IPAddress.Parse(txtIP.Text);
                    //将IP地址和端口号绑定到网络节点point上  
                    IPEndPoint point = new IPEndPoint(address, int.Parse(txtPort.Text.Trim()));
                    //此端口专门用来监听的  

                    //监听绑定的网络节点  
                    socketwatch.Bind(point);

                    //将套接字的监听队列长度限制为20  
                    socketwatch.Listen(20);

                    //负责监听客户端的线程:创建一个监听线程  
                    threadwatch = new Thread(watchconnecting);

                    //将窗体线程设置为与后台同步，随着主线程结束而结束  
                    threadwatch.IsBackground = true;

                    //启动线程     
                    threadwatch.Start();
                }
                catch (Exception ex)
                {
                    showLogs(ex.Message);
                    showError(ex);
                }

                btStart.Text = "停止";
            }
            else if (btStart.Text.Equals("停止"))
            {

                showLogs(DateTime.Now.Subtract(new TimeSpan(0, int.Parse(Form1.getInstance().txtMiniute.Text), 0)).ToString("yyyy-MM-dd HH:mm:ss") + "-" + "服务器端停止。\r\n");

                if (threadwatch != null)
                {
                    threadwatch.Interrupt();
                    threadwatch = null;
                }

                btStart.Text = "启动";
            }
        }


        //监听客户端发来的请求  
        static void watchconnecting()
        {
            try
            {
                Socket connection = null;

                //持续不断监听客户端发来的请求     
                while (true)
                {
                    try
                    {
                        connection = socketwatch.Accept();

                        //showLogs("开始循环发送");
                        Form1.getInstance().canSend = true;
                    }
                    catch (Exception ex)
                    {
                        //提示套接字监听异常     
                        //Console.WriteLine(ex.Message);
                        showLogs(ex.Message);
                        showError(ex);
                        break;
                    }

                    //获取客户端的IP和端口号  
                    IPAddress clientIP = (connection.RemoteEndPoint as IPEndPoint).Address;
                    int clientPort = (connection.RemoteEndPoint as IPEndPoint).Port;

                    //让客户显示"连接成功的"的信息  
                    //string sendmsg = "连接服务端成功！\r\n" + "本地IP:" + clientIP + "，本地端口" + clientPort.ToString();
                    //byte[] arrSendMsg = Encoding.UTF8.GetBytes(sendmsg);
                    //connection.Send(arrSendMsg);



                    //客户端网络结点号  
                    string remoteEndPoint = connection.RemoteEndPoint.ToString();
                    //显示与客户端连接情况
                    //Console.WriteLine("成功与" + remoteEndPoint + "客户端建立连接！\t\n");
                    showLogs(DateTime.Now.Subtract(new TimeSpan(0, int.Parse(Form1.getInstance().txtMiniute.Text), 0)).ToString("yyyy-MM-dd HH:mm:ss") + "-" + "接收到客户端" + clientIP + "(" + clientPort + ")" + "的连接...\r\n");

                    //添加客户端信息  
                    clientConnectionItems.Add(remoteEndPoint, connection);

                    //IPEndPoint netpoint = new IPEndPoint(clientIP,clientPort); 
                    IPEndPoint netpoint = connection.RemoteEndPoint as IPEndPoint;

                    //创建一个通信线程      
                    ParameterizedThreadStart pts = new ParameterizedThreadStart(recv);
                    Thread thread = new Thread(pts);
                    //设置为后台线程，随着主线程退出而退出 
                    thread.IsBackground = true;
                    //启动线程     
                    thread.Start(connection);
                }

                showLogs("与客户端的连接已断开！");
            }
            catch (Exception ex)
            {
                showLogs(ex.Message);
                showError(ex);
            }
        }

        /// <summary>
        /// 接收客户端发来的信息，客户端套接字对象
        /// </summary>
        /// <param name="socketclientpara"></param>    
        static void recv(object socketclientpara)
        {
            try
            {
                Socket socketServer = socketclientpara as Socket;
                socketServer.SendBufferSize = 0;

                while (true)
                {

                    //判断是否有要发送的命令
                    if (commandToSend.Count > 0)
                    {
                        CommandInfo currentCommand = null;
                        lock (socketclientpara)
                        {
                            currentCommand = commandToSend[0];
                            commandToSend.RemoveAt(0);
                        }

                        //byte[] datas = new byte[commandLine.Length / 2];
                        //for (int i = 0; i < commandLine.Length / 2; i++)
                        //{
                        //    datas[i] = Convert.ToByte(commandLine.Substring(i * 2, 2), 16);
                        //}
                        //socketServer.Send(datas);


                        /*服务器下发命令*/
                        //{
                        //    "switch": 0, /*switch:摄像头电源的控制状态，0=OFF，1=ON，非报警状态控制有效*/
                        //    "UploadInterval": 300, /* 采集终端上传数据的间隔时间(0-65535 秒)，为0时=不上传，UploadMode=1时无意义 */
                        //    "x_up": 0.0, /*x_up：x轴倾斜角度正常范围上限(≥-180°)(≤180°)，都等于0则不判断报警，超出正常范围时，摄像头电源打开，恢复正常时电源关闭*/
                        //    "y_up": 0.0, /*y_up：y轴倾斜角度正常范围上限(≥-180°)(≤180°)*/
                        //    "z_up": 0.0, /*z_up：z轴倾斜角度正常范围上限(≥-180°)(≤180°)*/
                        //    "x_down": 0.0, /*x_down：x轴倾斜角度正常范围下限(≥-180°)(≤180°)*/
                        //    "y_down": 0.0, /*y_down：y轴倾斜角度正常范围下限(≥-180°)(≤180°)*/
                        //    "z_down": 0.0 /*z_down：z轴倾斜角度正常范围下限(≥-180°)(≤180°)*/
                        //}
                        ///*设备回复*/
                        //{
                        //    "result": "OK" /*执行结果，"OK"，"ERR"*/
                        //}
                        //将字符串转为byte数组，commandLine的内容为json字符串
                        //byte[] datas = Encoding.UTF8.GetBytes(currentCommand.CommandStr);
                        //socketServer.Send(datas);
                        //showLogs("发送命令:" + currentCommand.CommandStr);
                        sendCommand(socketServer,currentCommand);

                        //将命令设置为发送成功

                    }
                    //将接收到的信息存入到内存缓冲区，并返回其字节数组的长度
                    try
                    {
                        if (socketServer.Available > 0)
                        {
                            String stationId = operateReceiveData(socketServer);

                            if (stationId != null && !endPointStrAndStationId.Keys.Contains(socketServer.RemoteEndPoint.ToString()))
                            {
                                showLogs("绑定" + socketServer.RemoteEndPoint.ToString() + "与" + stationId);
                                endPointStrAndStationId.Add(socketServer.RemoteEndPoint.ToString(), stationId);
                            }
                            else
                            {
                                //showLogs("跳过绑定" + socketServer.RemoteEndPoint.ToString() + "与" + stationId);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        clientConnectionItems.Remove(socketServer.RemoteEndPoint.ToString());

                        showLogs("Client Count:" + clientConnectionItems.Count);

                        //提示套接字监听异常  
                        showLogs("客户端" + socketServer.RemoteEndPoint + "已经中断连接" + "\r\n" + ex.Message + "\r\n" + ex.StackTrace + "\r\n");

                        //关闭之前accept出来的和客户端进行通信的套接字 
                        socketServer.Close();
                        break;
                    }


                    //获取命令
                    if (socketServer.RemoteEndPoint.ToString() != null && endPointStrAndStationId.ContainsKey(socketServer.RemoteEndPoint.ToString()))
                    {
                        //showLogs("获取命令");
                        getCommandFromDB(endPointStrAndStationId[socketServer.RemoteEndPoint.ToString()]);
                    }
                    else
                    {
                        //showLogs("跳过获取命令");
                    }

                    System.Threading.Thread.Sleep(int.Parse(ConfigurationManager.AppSettings["SleepTimeInSec"]) * 1000);
                }

                showLogs("跳出循环2");
            }
            catch (Exception ex)
            {
                showLogs(ex.Message);
                showError(ex);
            }
        }


        public static void showLogs(String logInfo)
        {
            if (Form1.getInstance().chkLogSortDesc.Checked)
            {
                Form1.getInstance().txtLog.Text = DateTime.Now.Subtract(new TimeSpan(0, int.Parse(Form1.getInstance().txtMiniute.Text), 0)).ToString("yyyy-MM-dd HH:mm:ss") + "-" + logInfo + "\r\n" + Form1.getInstance().txtLog.Text;
            }
            else
            {
                Form1.getInstance().txtLog.Text += DateTime.Now.Subtract(new TimeSpan(0, int.Parse(Form1.getInstance().txtMiniute.Text), 0)).ToString("yyyy-MM-dd HH:mm:ss") + "-" + logInfo + "\r\n";
            }

            LogHelper.WriteLog(DateTime.Now.Subtract(new TimeSpan(0, int.Parse(Form1.getInstance().txtMiniute.Text), 0)).ToString("yyyy-MM-dd HH:mm:ss") + "-" + logInfo);

            if (Form1.getInstance().txtLog.Lines.Length > int.Parse(ConfigurationManager.AppSettings["AutoClearLines"]))
            {
                Form1.getInstance().txtLog.Text = "";
                Form1.getInstance().logCounts.Text = "共有日志：0行";
            }
            else
            {
                Form1.getInstance().logCounts.Text = "共有日志：" + Form1.getInstance().txtLog.Lines.Length + "行";
            }
        }

        static String operateReceiveData(Socket socketServer)
        {
            //创建一个内存缓冲区，其大小为1024*1024字节  即1M     
            byte[] arrServerRecMsg = new byte[1024 * 1024];

            int length = socketServer.Receive(arrServerRecMsg);

            //将机器接受到的字节数组转换为人可以读懂的字符串     
            string strSRecMsg = Encoding.UTF8.GetString(arrServerRecMsg, 0, length);

            //直接处理JSON数据s
            return operateString(socketServer.RemoteEndPoint.ToString(), strSRecMsg, length);
        }

        static String operateString(String remoteEndPoint, String strSRecMsg, int length)
        {
            Boolean operateIt = false;
            String time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");

            //{"equi":"0000000001","battery":12.188828,"linked":1,"switch":0,"x":0.880,"y":1.710,"z":17.920,"x_up":0.0,"y_up":0.0,"z_up":0.0,"x_down":0.0,"y_down":0.0,"z_down":0.0}
            showLogs("接收到数据：" + strSRecMsg);
            if (strSRecMsg.ToLower().IndexOf("equi") >= 0 && strSRecMsg.ToLower().IndexOf("battery") >= 0 &&
                strSRecMsg.ToLower().IndexOf("linked") >= 0)
            {
                try
                {
                    UploadedData resultJSON = JsonConvert.DeserializeObject<UploadedData>(strSRecMsg);
                    showLogs("收到数据 " + strSRecMsg);

                    String sql1 = "INSERT INTO receive_history_new(station_id,data_id,value,created_time) values('" + resultJSON.Equi + "'," + 1 + ",'" + strSRecMsg + "','" + time + "')";
                    SqlHelper.ExecuteNonQuery(ConfigurationManager.AppSettings["ConnectString"], CommandType.Text, sql1, null);

                    //更新最新的数据
                    sql1 = @"SELECT count(*) FROM real_datas where station_id='" + resultJSON.Equi + "' and data_id=" + 1;
                    int count = int.Parse(SqlHelper.ExecuteScalar(ConfigurationManager.AppSettings["ConnectString"], CommandType.Text, sql1).ToString());
                    if (count == 0)
                    {
                        sql1 = "INSERT INTO real_datas(station_id,data_id,value,created_time) values('" + resultJSON.Equi + "'," + 1 + ",'" + strSRecMsg + "','" + time + "')";
                        SqlHelper.ExecuteNonQuery(ConfigurationManager.AppSettings["ConnectString"], CommandType.Text, sql1, null);
                    }
                    else
                    {
                        sql1 = "SELECT id,station_id,data_id,value from real_datas where station_id='" + resultJSON.Equi + "'";
                        DataSet ds = SqlHelper.GetDataSet(ConfigurationManager.AppSettings["ConnectString"], CommandType.Text, sql1, null);
                        int id = int.Parse(ds.Tables[0].Rows[0]["id"].ToString());

                        sql1 = "UPDATE real_datas set value = '" + strSRecMsg + "',created_time = '" + time + "' where id= " + id;
                        SqlHelper.ExecuteNonQuery(ConfigurationManager.AppSettings["ConnectString"], CommandType.Text, sql1, null);
                    }

                    lastGetData = DateTime.Now;
                    return resultJSON.Equi;
                }
                catch (Exception ex)
                {
                    showLogs(ex.Message);
                    return null;
                }
            }
            else
            {
                showLogs("未处理数据=" + strSRecMsg);
                return null;
            }

        }


        private void button3_Click(object sender, EventArgs e)
        {
            if (btStart.Text.Equals("停止"))
            {
                btStart.PerformClick();
                Application.Exit();
            }
            else
            {
                Application.Exit();
            }
        }

        private void btClear_Click(object sender, EventArgs e)
        {
            txtLog.Text = "";
        }

        private static void showError(Exception ex)
        {
            Form1.getInstance().txtError.Text += DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " " + ex.StackTrace;
        }
        private void button2_Click_1(object sender, EventArgs e)
        {
            txtError.Text = "";
        }

        private void tmrForStart_Tick(object sender, EventArgs e)
        {
            btStart.PerformClick();
            tmrForStart.Enabled = false;
        }

        private void btClearErrorLogs_Click(object sender, EventArgs e)
        {
            txtError.Text = "";
        }



        private void btRestart_Click(object sender, EventArgs e)
        {
            restartApp();
        }

        private void restartApp()
        {
            if (btStart.Text.Equals("停止"))
            {
                btStart.PerformClick();
            }


            //向日志文件中写入重启时间
            string logFilePath = Path.GetDirectoryName(Application.ExecutablePath) + "log.txt";
            string logMessage = "重启记录" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "\n";

            using (StreamWriter writer = File.AppendText(logFilePath))
            {
                writer.WriteLine($"{DateTime.Now} - {logMessage}");
            }

            Application.Restart();
        }

        private void tmrAutoRestart_Tick(object sender, EventArgs e)
        {
            Int32 waitInMiniutes;

            if (Int32.TryParse(txtNoDataInMiniutes.Text.Trim(), out waitInMiniutes))
            {
                Console.WriteLine("等待" + waitInMiniutes + "分钟");
                if (lastGetData != null && DateTime.Now.Subtract(lastGetData).TotalMinutes > waitInMiniutes) //有5分钟没有接收到数据了。
                {
                    restartApp();
                }
            }
            else
            {
                Console.WriteLine("未设定等待时间");
                return;
            }

        }

        private void btTest_Click(object sender, EventArgs e)
        {
            String command = "{\"equi\":\"0000000001\",\"battery\":10.795910,\"linked\":1,\"switch\":1,\"x\":0.620,\"y\":1.240,\"z\":-12.970,\"x_up\":0.0,\"y_up\":0.0,\"z_up\":0.0,\"x_down\":0.0,\"y_down\":0.0,\"z_down\":0.0}";
            operateString(null, command, command.Length);
        }

        private static void getCommandFromDB(String stationId) {
            try
            {
                String sql1 = "Select * from command_info where station_id = '" + stationId + "' and is_finished = 0";
                DataSet ds = SqlHelper.GetDataSet(ConfigurationManager.AppSettings["ConnectString"], CommandType.Text, sql1, null);

                if (ds != null && ds.Tables[0].Rows.Count > 0)
                {
                    //showLogs("获取到" + ds.Tables[0].Rows.Count + "条命令");
                    for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
                    {
                        String comandInfo = ds.Tables[0].Rows[i]["command_value"].ToString();
                        String id = ds.Tables[0].Rows[i]["id"].ToString();

                        CommandInfo commandInfo = new CommandInfo();
                        commandInfo.CommandStr = comandInfo;
                        commandInfo.CommandId = id;

                        showLogs("读取到命令：" + commandInfo.CommandStr);
                        commandToSend.Add(commandInfo);
                    }
                }
                else
                {
                    //showLogs("未获取到命令");
                }
            }
            catch (Exception ex) {
                showLogs("获取命令失败，" + ex.Message);
            }
        }

        private static void sendCommand(Socket socketServer,CommandInfo currentCommand)
        {

            try
            {
                byte[] datas = Encoding.UTF8.GetBytes(currentCommand.CommandStr);
                socketServer.Send(datas);
                showLogs("发送命令:" + currentCommand.CommandStr);

                showLogs("发送命令" + currentCommand.CommandStr + "成功");

                String sql1 = "update command_info set is_finished = 1 where id='" + currentCommand.CommandId + "'";
                SqlHelper.ExecuteNonQuery(ConfigurationManager.AppSettings["ConnectString"], CommandType.Text, sql1, null);

            }
            catch (Exception ex)
            {

                showLogs("发送命令"+currentCommand.CommandStr+"失败," + ex.Message);

                String sql1 = "update command_info set is_finished = 1 where id='" + currentCommand.CommandId + "'";
                SqlHelper.ExecuteNonQuery(ConfigurationManager.AppSettings["ConnectString"], CommandType.Text, sql1, null);
            }
        }
    }

}

